package com.example.gate.netty;

import com.example.game.CReq;
import com.example.game.CResp;
import com.google.protobuf.ByteString;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.*;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.nio.ByteOrder;
import java.util.List;

/**
 * Netty TCP服务器
 * 支持M0Base.proto协议
 * 
 * @author: Allen
 * @create: 2025/1/27 13:00
 * @description: Netty TCP服务器
 **/
@Slf4j
@Component
public class TcpServer {
    
    @Value("${gate.tcp.port:8000}")
    private int tcpPort;
    
    @Value("${gate.tcp.boss.threads:1}")
    private int bossThreads;
    
    @Value("${gate.tcp.worker.threads:4}")
    private int workerThreads;
    
    @Autowired
    private MessageHandler messageHandler;
    
    private EventLoopGroup bossGroup;
    private EventLoopGroup workerGroup;
    private Channel serverChannel;
    
    @PostConstruct
    public void start() throws Exception {
        log.info("启动Netty TCP服务器，端口: {}", tcpPort);
        
        bossGroup = new NioEventLoopGroup(bossThreads);
        workerGroup = new NioEventLoopGroup(workerThreads);
        
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            
                            // 添加长度字段解码器，处理粘包拆包
                            pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.BIG_ENDIAN, 1048576, 0, 4, 0, 4, true));
                            pipeline.addLast(new LengthFieldPrepender(ByteOrder.BIG_ENDIAN, 4, 0, false));
                            // 添加protobuf编解码器
                            pipeline.addLast(new ProtobufDecoder());
                            pipeline.addLast(new ProtobufEncoder());
                            
                            // 添加业务处理器
                            pipeline.addLast(messageHandler);
                        }
                    })
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childOption(ChannelOption.TCP_NODELAY, true);
            
            ChannelFuture future = bootstrap.bind(tcpPort).sync();
            serverChannel = future.channel();
            
            log.info("Netty TCP服务器启动成功，监听端口: {}", tcpPort);
            
        } catch (Exception e) {
            log.error("Netty TCP服务器启动失败", e);
            throw e;
        }
    }
    
    @PreDestroy
    public void stop() {
        log.info("关闭Netty TCP服务器");
        
        if (serverChannel != null) {
            serverChannel.close();
        }
        
        if (bossGroup != null) {
            bossGroup.shutdownGracefully();
        }
        
        if (workerGroup != null) {
            workerGroup.shutdownGracefully();
        }
        
        log.info("Netty TCP服务器已关闭");
    }
    
    /**
     * Protobuf解码器
     */
    public static class ProtobufDecoder extends MessageToMessageDecoder<ByteBuf> {

        @Override
        protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
            if (in.readableBytes() < 4) {
                return;
            }

            in.markReaderIndex();
            int secret = in.readInt();//加密类型
            int length = in.readInt();//包体长度


            if (in.readableBytes() < length) {
                in.resetReaderIndex();
                return;
            }

            byte[] data = new byte[length];
            in.readBytes(data);

            try {
                CReq request = CReq.parseFrom(data);
                out.add(request);
            } catch (Exception e) {
                log.error("Protobuf解码失败", e);
                ctx.close();
            }
        }
    }

    /**
     * Protobuf编码器
     */
    public static class ProtobufEncoder extends MessageToByteEncoder<CResp> {
        @Override
        protected void encode(ChannelHandlerContext ctx, CResp msg, ByteBuf out) throws Exception {
            byte[] data = msg.toByteArray();
            out.writeInt(0);
            out.writeInt(data.length);
            out.writeBytes(data);
        }
    }

} 